package jch.learn.java.advanced.chapter1_stream.streams;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Stream;

// 从迭代到流的操作
public class CountLongWords {

    public static void main(String[] args) throws IOException, URISyntaxException {
        // 读取文件 | 并装入list
        String contents = new String(Files.readAllBytes(Paths.get(CountLongWords.class.getResource("/gutenberg/alice30.txt").toURI())), StandardCharsets.UTF_8);
        List<String> words = Arrays.asList(contents.split("\\PL+"));

        System.out.println("以迭代方式计算单词长度大于12的数量：");
        long count = 0;
        for (String w : words) {
            if (w.length() > 12) count++;
        }
        System.out.println(count);

        System.out.println("使用stream()顺序流方式计算单词长度大于12的数量：");
        // java.util.stream.Stream<T> 类的方法
        // 使用Stream<T> filter(Predicate<? super T> p) | 产生一个满足条件p的新流
        // long count() 计算当前流中元数的数量。是一个终止操作
        count = words.stream().filter(w -> w.length() > 12).count();
        System.out.println(count);

        System.out.println("使用parallelStream()并行流方式计算：");
        // java.util.Collection<E> 类的方法
        // default Stream<E> stream() 产生当前集合的顺序流
        // default Stream<E> parallelStream() 产生当前集合的并行流
        count = words.parallelStream().filter(w -> w.length() > 12).count();
        System.out.println(count);


        // 流与集合的差异：
        // 1、流并不存储其元素。元素存储在底层的集合中，或按需生成。
        // 2、流的操作不会修改其数据源，而是会产生新的流。
        // 3、流的操作是尽可能惰性执行的。即：直至需要其结果时，操作才会执行。【某些情况下可操作无限流】

        // 操作流的典型流程：
        // 1、创建
        // 2、指定将初始流转换为其他流的中间操作，可能包含多个步骤。
        // 3、终止操作，产生结果。该操作会强制执行之前的惰性操作。此后，该流就不可用了。

        // 中间操作

        // filter、map、flatMap
        // java.util.stream.Stream
        // Stream<T> filter(Predicate<? super T> predicate) 产生一个流，包含满足当前断言条件的所有元素。
        // <R> Stream<R> map(Function<? super T,? extends R> mapper) 产生一个流，包含将mapper应用于当前流中所有元素产生的结果
        // <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper) 产生一个流，通过将mapper应用于当前流中所有元素产生的结果连接到一起而获得的。（每个结果相当于一个流）

        // 产生一个流，包含满足条件的元素
        Stream<String> longWords = words.stream().filter(w -> w.length() > 12);
//        System.out.println("输出longWords: ");
//        longWords.forEach(System.out::println);
        // 产生一个流，将longWords流中的元素转为大写
        Stream<String> lowercaseWords = longWords.map(String::toLowerCase);
//        System.out.println("输出lowercaseWords: ");
//        lowercaseWords.forEach(System.out::println);
        // 按照 letters 方法 拼接流输
        Stream<String> flatResult = lowercaseWords.flatMap(w -> letters(w));
//        System.out.println("输出flatResult: ");
//        flatResult.forEach(System.out::println);

        // 抽取子流和连接流
        // java.util.Stream
        // Stream<T> limit(long maxSize) 产生一个流，包含当前流中最初的maxSize个元素。
        // Stream<T> skip(long n) 产生一个流，它的元素为当前流除去前n个元素之外的所有元素。
        // static <T> Stream<T> concat(Stream<? extends T> a,Stream<? extends T> b) 产生一个流，它的元素为a和b的元素（b的元素在a的元素之后） 连接两个流产生一个新流。

        Stream<String> limits = words.stream().limit(5);
        limits.forEach(System.out::println);
        Stream<String> skip1 = words.stream().limit(5).skip(3);
        System.out.println();
        skip1.forEach(System.out::println);
        Stream<String> combined = Stream.concat(letters("test"),letters("stream"));
        System.out.println();
        combined.forEach(System.out::println);

        // 其他流转换
        // java.util.stream.Stream
        // Stream<T> distinct() 产生一个流，包含当前流中所有不同元素
        // Stream<T> sorted() 产生一个流，元素为当前流的元素按照顺序排列的（自然顺序）
        // Stream<T> sorted(Comparator<? super T> comparator) 产生一个流，元素按照给定规则排序（元素需实现Comparable）
        // Stream<T> peek(Consumer<? super T> action) 产生一个流，元素与当前流元素相同，在获取元素前都会经过action方法。
        // 产生一个流，元素为当前流去重后的元素
        Stream<String> distinctStream = Stream.of("a","a","1","a","q").distinct();
        distinctStream.forEach(System.out::println);

        Stream<String> longest = words.stream().sorted(Comparator.comparing(String::length).reversed());
        longest.forEach(System.out::println);

        Object[] ws = words.stream().peek(System.out::println).limit(5).toArray();
        System.out.println(Arrays.toString(ws));

        // 简单约简 （终结操作 terminal operation: 即 将流约简为可在程序中使用的非流值。）
        // java.util.stream.Stream
        // Optional<T> max(Comparator<? super T> comparator) 产生该流的最大元素，使用给定比较器定义的排序规则，若为空，则产生一个空的Optional对象。
        Optional<String> largest = words.stream().max(String::compareToIgnoreCase);
        System.out.println("largest: " + largest.orElse(""));
        // Optional<T> min(Comparator<? super T> comparator) 产生该流的最小元素，使用给定比较器定义的排序规则，若为空，则产生一个空的Optional对象。

        // Optional<T> findFirst() 产生该流的第一个元素，若为空，则产生一个空的Optional对象。
        Optional<String> startsWithQ = words.stream().filter(s -> s.startsWith("Q")).findFirst();
        System.out.println("startsWithQ findFirst:" + startsWithQ.orElse(""));
        // Optional<T> findAny() 产生该流的任意一个元素，若为空，则产生一个空的Optional对象。
        Optional<String> findWithQ = words.stream().filter(s -> s.startsWith("Q")).findAny();
        System.out.println("findWithQ findAny:" + findWithQ.orElse(""));

        // boolean anyMatch(Predicate<? super T> predicate) 该流中任意元素匹配给定断言条件
        boolean aWordStartsWithQ = words.stream().parallel().anyMatch(s -> s.startsWith("Q"));
        System.out.println("aWordStartsWithQ:" + aWordStartsWithQ);
        // boolean allMatch(Predicate<? super T> predicate) 该流中全部元素匹配给定断言条件
        // boolean noneMatch(Predicate<? super T> predicate) 该流中没有任何元素匹配给定断言条件
    }

    public static Stream<String> letters(String s) {
        List<String> result = new ArrayList<>();
        for (int i = 0; i < s.length(); i++) {
            result.add(s.substring(i, i + 1));
        }
        return result.stream();
    }

}
